package com.xms.sdk.client.aggroot;

import com.xms.core.enums.OperationStage;
import com.xms.core.enums.OperationType;
import com.xms.core.exception.XmsException;
import com.xms.plugin.service.IFormPluginExecutor;
import com.xms.schema.entity.Attribute;
import com.xms.schema.entity.Entity;
import com.xms.schema.entity.RelationShip;
import com.xms.schema.service.attribute.IAttributeFinderService;
import com.xms.schema.service.relationship.IRelationShipFinderService;
import com.xms.sdk.client.DataProviderBase;
import com.xms.sdk.core.AggregateRootMetaData;
import com.xms.sdk.core.EntityAttributeMetadata;
import com.xms.sdk.core.EntityReference;
import com.xms.sdk.service.IDataCreater;
import com.xms.utils.CollectionUtil;
import com.xms.utils.StringUtil;
import com.xms.utils.UUIDUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * <p>
 * AggCreater
 * </p>
 *
 * @author migo
 * @since 2021/9/8
 */
@Service
public class AggCreater extends DataProviderBase implements IAggCreater{
    private IDataCreater _dataCreater;
    private IAttributeFinderService _attributeFinderService;
    private IRelationShipFinderService _relationShipFinderService;
    private IFormPluginExecutor<AggregateRoot, AggregateRootMetaData> _formPluginExecutor;
    @Autowired
    public void AggCreater(IDataCreater dataCreater,
                           IAttributeFinderService attributeFinderService,
                           IRelationShipFinderService relationShipFinderService,
                           IFormPluginExecutor<AggregateRoot, AggregateRootMetaData> formPluginExecutor) {
        _dataCreater = dataCreater;
        _attributeFinderService = attributeFinderService;
        _relationShipFinderService = relationShipFinderService;
        _formPluginExecutor = formPluginExecutor;
    }

    @Override
    public UUID create(AggregateRoot aggregateRoot, UUID objectId, UUID systemFormId) throws XmsException{
        return this.create(aggregateRoot, objectId, systemFormId, false);
    }

    @Override
    public UUID create(AggregateRoot aggregateRoot, UUID objectId, UUID systemFormId, boolean ignorePermissions) throws XmsException {
        AggregateRootMetaData aggRootMetaData = GetAggregateRootMetaData(aggregateRoot, systemFormId);
        UUID thisId = UUIDUtil.get();
        try
        {
            internalOnCreate(aggregateRoot, OperationStage.PreOperation, aggRootMetaData);
            //关联Id
            //thisId = objectId;
            for (RefEntity c : aggregateRoot.ChildEntities)
            {
                String name = c.Name, relationshipname = c.Relationshipname, refname = "";
                if (StringUtil.notEmpty(relationshipname))
                {
                    RelationShip relationShipMetas = _relationShipFinderService.getByName(c.Relationshipname);
                    if (null != relationShipMetas && relationShipMetas.getReferencedentityid().equals(c.Entityid))
                    {
                        refname = relationShipMetas.getReferencingattributename();
                    }
                    if (StringUtil.notEmpty(refname))
                    {
                        c.Entity.setValue(refname, new EntityReference(aggregateRoot.MainEntity.Name, thisId));
                    }
                }
            }

            List<com.xms.core.data.Entity> childEntities = aggregateRoot.ChildEntities.stream().map(x -> x.Entity).collect(Collectors.toList());
            List<String> entityNames = childEntities.stream().map(x->x.Name).distinct().collect(Collectors.toList());
            for (String item : entityNames)
            {
                List<com.xms.core.data.Entity> items = childEntities.stream().filter(n -> n.Name.equalsIgnoreCase(item)).collect(Collectors.toList());
                List<com.xms.core.data.Entity> creatingRecords = items.stream().filter(n -> n.Name.equalsIgnoreCase(item) && UUIDUtil.isEmpty(n.getIdValue())).collect(Collectors.toList());
                if (CollectionUtil.notEmpty(creatingRecords))
                {
                    _dataCreater.createMany(creatingRecords);
                }
            }
            aggregateRoot.MainEntity.setIdValue(thisId);
            _dataCreater.create(aggregateRoot.MainEntity);
            internalOnCreate(aggregateRoot, OperationStage.PostOperation, aggRootMetaData);
        }
        catch (Exception e)
        {
            onException(e);
        }
        return thisId;
    }

    private AggregateRootMetaData GetAggregateRootMetaData(AggregateRoot aggregateRoot, UUID systemFormId) throws XmsException {
        AggregateRootMetaData aggRootMetaData = new AggregateRootMetaData();
        Entity entityMetadata = getEntityMetaData(aggregateRoot.MainEntity.Name);
        List<Attribute> attributeMetadatas = _attributeFinderService.getByEntityId(entityMetadata.getEntityid());
        EntityAttributeMetadata eam = new EntityAttributeMetadata();
        eam.EntityMetadata = entityMetadata;
        eam.AttributeMetadatas = attributeMetadatas;
        aggRootMetaData.MainMetadata = eam;
        aggRootMetaData.SystemFormId = systemFormId;

        aggRootMetaData.ListMetadatas = new HashMap<>();
        for (RefEntity refEntity : aggregateRoot.ChildEntities)
        {
            entityMetadata = getEntityMetaData(refEntity.Name);
            attributeMetadatas = _attributeFinderService.getByEntityId(entityMetadata.getEntityid());
            eam = new EntityAttributeMetadata();
            eam.EntityMetadata = entityMetadata;
            eam.AttributeMetadatas = attributeMetadatas;
            if (aggRootMetaData.ListMetadatas.containsKey(refEntity.Name))
            {
                aggRootMetaData.ListMetadatas.put(refEntity.Name, eam);
            }
        }
        return aggRootMetaData;
    }

    private void internalOnCreate(AggregateRoot data, OperationStage stage, AggregateRootMetaData aggRootMetaDatas)
    {
        //plugin
        UUID entityId = aggRootMetaDatas.MainMetadata.EntityMetadata.getEntityid();
        _formPluginExecutor.execute(entityId, aggRootMetaDatas.SystemFormId, OperationType.Update, stage, data, aggRootMetaDatas);
        if (stage == OperationStage.PreOperation)
        {
            //event publishing
            //_eventPublisher.Publish(new AggRootCreatingEvent(data) { AggRootMetaData = aggRootMetaDatas });
        }
        else if (stage == OperationStage.PostOperation)
        {
            //event publishing
            //_eventPublisher.Publish(new AggRootCreatedEvent(data) { AggRootMetaData = aggRootMetaDatas });
        }
    }
}
